#ifndef __TOOL_H_
#define __TOOL_H_
#include <locale>
#include <string>
#include <vector>
#include <codecvt>
#include <chrono>
#include <ctime>
#include <random>
namespace iocp
{
#if defined(_WIN32)
#define LOCALTIME(X, Y) localtime_s(X, Y)
#else
#define LOCALTIME(X, Y) localtime_r(Y, X)
#endif

	// convert wchar_t* to char* with '?' as default character
	inline char* wchar_to_char(const wchar_t* src, unsigned int size, char* dst, const std::locale& loc = std::locale())
	{
		std::use_facet<std::ctype<wchar_t>>(loc).narrow(src, src + size, '?', dst);
		return dst;
	}

	// convert char* to wchar_t*
	inline wchar_t* char_to_wchar(const char* src, unsigned int size, wchar_t* dst, const std::locale& loc = std::locale())
	{
		std::use_facet<std::ctype<wchar_t>>(loc).widen(src, src + size, dst);
		return dst;
	}

	// convert string to wstring
	inline std::wstring to_wstring(std::string const& str, const std::locale& loc = std::locale())
	{
		std::vector<wchar_t> buf(str.size());
		std::use_facet<std::ctype<wchar_t>>(loc).widen(str.data(), str.data() + str.size(), buf.data());
		return std::wstring(buf.data(), buf.size());
	}

	// convert wstring to string with '?' as default character
	inline std::string to_string(std::wstring const& str, const std::locale& loc = std::locale())
	{
		std::vector<char> buf(str.size());
		std::use_facet<std::ctype<wchar_t>>(loc).narrow(str.data(), str.data() + str.size(), '?', buf.data());

		return std::string(buf.data(), buf.size());
	}

	// convert UTF-8 string to wstring
	template<typename T>
	inline std::wstring utf8_to_wstring(T&& str)
	{
		std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
		return myconv.from_bytes(std::forward<T>(str));
	}

	// convert wstring to UTF-8 string
	template<typename T>
	inline std::string wstring_to_utf8(T&& str)
	{
		std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
		return myconv.to_bytes(std::forward<T>(str));
	}

	inline auto GetCurrTickCount() -> std::chrono::system_clock::duration
	{
		return std::chrono::system_clock::now().time_since_epoch();
	}

	inline unsigned int GetDayOfWeek()
	{
		std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		struct tm local_time;

		LOCALTIME(&local_time, &tt);

		return local_time.tm_wday == 0 ? local_time.tm_wday : 7;
	}

	inline unsigned int GetDayOfMonth()
	{
		std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		struct tm local_time;
		LOCALTIME(&local_time, &tt);
		return local_time.tm_mday;
	}

	inline unsigned int GetCurrMonth()
	{
		std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		struct tm local_time;
		LOCALTIME(&local_time, &tt);
		return local_time.tm_mon + 1;
	}

	inline unsigned int GetCurrYear()
	{
		std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		struct tm local_time;
		LOCALTIME(&local_time, &tt);
		return local_time.tm_year + 1900;
	}

	inline tm GetCurrTime()
	{
		std::time_t tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		struct tm local_time;
		LOCALTIME(&local_time, &tt);
		return local_time;		// RVO
	}

	inline int GetRandNumber(int min, int max)
	{
		std::default_random_engine e(static_cast<unsigned int>(time(nullptr)));
		std::uniform_int_distribution<int> u(min, max);
		return u(e);
	}
}
#endif